/**
 * @constructor
 * @param(Queue) inputQueue
 */
function CanvasMouseListener(inputQueue) {
	
	this.inputQueue = inputQueue;
	
	var self = this;
	$("#canvas").bind( "mouseup", function(e){ self.onMouseUp(e); } );
	$("#canvas").bind( "mousedown", function(e){ self.onMouseDown(e); } );
	$("#canvas").bind( "mousemove", function(e){ self.onMouseMove(e); } );
	
	this.onMouseUp = function(e) {
		if(e.which==1) {
			this.createMouseEvent(e, MouseEventType.MOUSE_LEFT_UP);
		} else if(e.which==3) {
			this.createMouseEvent(e, MouseEventType.MOUSE_RIGHT_UP);
		}
		
	};
	
	this.onMouseDown = function(e) {
		if(e.which==1) {
			this.createMouseEvent(e, MouseEventType.MOUSE_LEFT_DOWN);
		} else if(e.which==3) {
			this.createMouseEvent(e, MouseEventType.MOUSE_RIGHT_DOWN);
		}
	};
	
	this.onMouseMove = function(e) {
		this.createMouseEvent(e, MouseEventType.MOUSE_MOVE);
	};
	
	this.createMouseEvent = function(e, mouseEventType) {
		var xpos, ypos;
		if(e.offsetX==undefined) {//firefox
		    xpos = e.pageX-$('#canvas').offset().left;
		    ypos = e.pageY-$('#canvas').offset().top;
		} else {//others
		    xpos = e.offsetX;
		    ypos = e.offsetY;
		}
		if(xpos >= 0 && ypos >= 0 && xpos < $('#canvas').width() && ypos < $('#canvas').height()) {
			this.inputQueue.push(new MouseEvent(xpos, ypos, mouseEventType));
		}		
	};
}

/**
 * @Constructor
 */
function MouseEvent(x, y, mouseEventType) {
	this.x = x;
	this.y = y;
	this.mouseEventType = mouseEventType;
}

/**
 * @constructor
 * @param capacity
 * @returns {Queue}
 */
function Queue(capacity) {
	
	this.capacity = capacity;
	this.container = [];
	this.size = 0;
	
	/**
	 * @public
	 * @param element
	 */
	this.push = function(element) {
		if(this.size<this.capacity) {
			this.container.push(element);
			this.size++;
			return true;
		}
		return false;
	};
	
	/**
	 * @public
	 */
	this.pop = function() {
		if(this.size==0) {
			return null;
		}
		var element = this.container.shift();
		this.size--;
		return element;
	};
	
	/**
	 * @public
	 * @returns {Boolean}
	 */
	this.isEmpty = function() {
		return this.size==0;
	};
	
	/**
	 * @public
	 * @returns {Boolean}
	 */
	this.isFull = function() {
		return this.size==this.capacity;
	};
}

function ControlsInputManager(inputQueue, area, terrainOnlyArea) {
	
	/*
	 * TODO: All input coming from this should pass through the inputQueue (and be processed in the game loop) so as to avoid 
	 * race conditions
	 */
	
	this.inputQueue = inputQueue;
	this.area = area;
	this.terrainOnlyArea = terrainOnlyArea;
	
	var self = this;
	
	$("#gridButton").bind( "mouseup", function(e){ self.onGridButtonMouseUp(e); } );
	$("#clearObstaclesButton").bind( "mouseup", function(e){ self.onClearObstaclesButtonMouseUp(e); } );
	$("#moveButton").bind( "mouseup", function(e){ self.onMoveButtonMouseUp(e); } );
	$("#sloMoCheckBox").click(function(e){ self.onSloMoCheckBoxClick(e); } );
	$("#debugCheckBox").click(function(e){ self.onDebugCheckBoxClick(e); } );
	
	$("#decreasePathWaitTimeButton").click(function(e){ self.onDecreasePathWaitTimeButtonClick(e); } );
	$("#increasePathWaitTimeButton").click(function(e){ self.onIncreasePathWaitTimeButtonClick(e); } );
	
	$('#distanceCalculatorSelect').change(function(e){ self.onDistanceCalculatorSelectorChange(e); } );
	
	this.onGridButtonMouseUp = function(e) {
		if(SHOW_GRID) {
			SHOW_GRID = false;
			this.gridButton.prop("value", "Show Grid");
		} else {
			SHOW_GRID = true;
			this.gridButton.prop("value", "Hide Grid");
		}
	};
	
	this.onClearObstaclesButtonMouseUp = function(e) {
		for(var x = 0; x<this.area.getWidth(); x++) {
			for(var y = 0; y<this.area.getHeight(); y++) {
				this.area.edit(x, y, TerrainType.PASSABLE);
				this.terrainOnlyArea.edit(x, y, TerrainType.PASSABLE);
			}
		}
	};
	
	this.onMoveButtonMouseUp = function(e) {
		$("#moveButton").hide();
		$("#clearObstaclesButton").hide();
		$("#distanceCalculatorControl").hide();
		this.inputQueue.push(new MoveInputEvent());
	};
	
	this.onSloMoCheckBoxClick = function(e) {
		if($("#sloMoCheckBox").prop('checked')) {
			FIXED_STEP_IDEAL_DURATION_MS = 1000/5;
		} else {
			FIXED_STEP_IDEAL_DURATION_MS = 1000/50;
		}
		FIXED_UPDATES_IN_A_SECOND = 1000/FIXED_STEP_IDEAL_DURATION_MS;
	};
	
	this.onDebugCheckBoxClick = function(e) {
		if($("#debugCheckBox").prop('checked')) {
			this.inputQueue.push(new ToggleDebugEvent(true));
		} else {
			this.inputQueue.push(new ToggleDebugEvent(false));
		}
	};
	
	this.onDecreasePathWaitTimeButtonClick = function(e) {
		if(UPDATES_TO_WAIT_UNTIL_PATH_RECALCULATION == 0) {
			return;
		}
		UPDATES_TO_WAIT_UNTIL_PATH_RECALCULATION -= 10;
		$('#pathWaitTimeDiv').text(""+UPDATES_TO_WAIT_UNTIL_PATH_RECALCULATION);
	};
	
	this.onIncreasePathWaitTimeButtonClick = function(e) {
		if(UPDATES_TO_WAIT_UNTIL_PATH_RECALCULATION == 500) {
			return;
		}
		UPDATES_TO_WAIT_UNTIL_PATH_RECALCULATION += 10;
		$('#pathWaitTimeDiv').text(""+UPDATES_TO_WAIT_UNTIL_PATH_RECALCULATION);
	};
	
	this.onDistanceCalculatorSelectorChange = function(e) {
		if($('#distanceCalculatorSelect').val() == "E") {
			DISTANCE_CALCULATOR = DISTANCE_CALCULATOR_ECULID;
		} else if($('#distanceCalculatorSelect').val() == "MC") {
			DISTANCE_CALCULATOR = DISTANCE_CALCULATOR_MOD_CHEB;
		}
	};
}

function MoveInputEvent() {}
function ToggleDebugEvent(value) {
	this.value = value;
}